我們前面講了許多Spring應用開發,但當我們開發好一套系統,勢必要有一套API手冊,不然前端開發者就會很辛苦的難以開發,都要等待您的API出來才能測試及開發,有沒有覺得小編像羅志祥,轉角遇到愛,等等!不是那個SWAG,我是威斯丁,小編其實是轉角遇到金光黨,你要怎麼整合金光黨的包裝呢?你也是要等它出完招數,以後你才知道怎麼測試與整合金光黨嗎!對不對!我好無言!寫前端都會先刻假GUI,有的後端工程師就會看到,突然,好喔,那我配合你,那這樣更累,這就是人生,充滿了蜜罐,他還很開心,哎~不對,今天不講資安,所以今天小編就把這個歐巴桑賣魚系統,透過大家悉知的Swagger來做一個簡易的API手冊,讓小編來跟大家說如何把API手冊做的詳細、做的快速,本日章節將提出如何配置個Swagger專有的說明註解(ApiOperation、ApiResponses),亦可透過Swagger操作手冊進行觸發個項API進行測試,以便提供前端開發者了解API的回覆結構及運作方法,可提高前後端分工效率,如此一來,我們就擁有一個系統規格的討論工具囉!我是小編威斯丁,帶你一同去探討SWAGGER!等等!想到這邊,我忘記說其實我上一篇是想推薦給我前區塊鏈公司用的,但那時可能太忙我忘了,身為開發者在區塊鏈的你,推薦你用那架構,效能特優的!我是小編威斯丁!現在就開始!
Swagger 目前只有提供在JAX-RS、Spring WEB REST、Jersey等專案的整合,Springfox 是一個將 Swagger 封裝為可以整合至基於 Spring 生態系統的套件,並且提供了 springfox-swagger-ui 將 Swagger UI 整合至 Server後端,為一種伺服器轉導(SSR,Server Side Render),故透過Spring Boot 啟動後,就可以直接進入 Swagger UI 的操作頁面。相關程式碼配置如下,請參考。
配置Swagger WebMvc 配置組態檔
@Configuration
@EnableWebMvc
public class SwaggerWebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
//預設攔截路徑
registry.addMapping("/**")
//表示允许網域發發起哪些請求,這裡表示支援HEAD,GET,PUT,POST,DELETE,PATCH
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//Swagger路徑映射配置
registry.addRedirectViewController("/docApi/v2/api-docs", "/v2/api-docs");
registry.addRedirectViewController("/docApi/swagger-resources/configuration/ui", "/swagger-resources/configuration/ui");
registry.addRedirectViewController("/docApi/swagger-resources/configuration/security", "/swagger-resources/configuration/security");
registry.addRedirectViewController("/docApi/swagger-resources", "/swagger-resources");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 新增Swagger對映路徑
registry.addResourceHandler("/docApi/swagger-ui.html**").addResourceLocations("classpath:/META-INF/resources/swagger-ui.html");
registry.addResourceHandler("/docApi/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
配置系統服務說明及相關API 觸發測試配置內容
@Configuration
@EnableSwagger2
@EnableWebMvc
@Component
public class SwaggerConfig {
@Value("${server.servlet.context-path}")
String serviceBasePath;
@Bean
public Docket apiDefault() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("sw.spring.sample.soa"))
.paths(PathSelectors.any())
.build()
.enable(true)
.consumes(Sets.newHashSet(MediaType.APPLICATION_JSON_VALUE))
.produces(Sets.newHashSet(MediaType.APPLICATION_JSON_VALUE));
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("WEISTING's Seafood RESTful API Information")
.description("Definition of the Asia area Seafood product Retailer from Taiwan and China.")
.license("Darius Weisting")
.version("1.0")
.contact(new Contact("Darius Weisting",null,"showwei0217@gmail.com"))
.build();
}
}
依據各API控制器群組名稱,及配置API功能名稱與敘述,並設置各種RESTful API的回覆狀態內容敘述。
@Api(tags = "Taiwan Area Retailer API")
@RestController
public class ProductController extends ControllerBase{
@Resource(name="seaFoodRetailService",type = SeaFoodRetailerService.class)
SeaFoodRetailerService seaFoodRetailService;
Logger logger = LoggerFactory.getLogger(ProductController.class);
@GetMapping(
value="/${sea.food.api.taiwan}/list",
produces = MediaType.APPLICATION_JSON_VALUE
)
@ApiOperation(value = "Returns list sea food products", notes = "Returns a list sea food products base on GET Method.", response = List.class)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Successful retrieval of sea food list products ! ", response = List.class),
@ApiResponse(code = 400, message = "Sea food resource not found ! "),
@ApiResponse(code = 500, message = "Internal server error") })
ResponseEntity<Flux> listSeaFood() {
return new ResponseEntity<>(Mono.just(seaFoodRetailService.listSeaFoodProducts()).flatMapMany(Flux::fromIterable),HttpStatus.OK);
}
@GetMapping(
value="/${sea.food.api.taiwan}/find/{id}",
produces = MediaType.APPLICATION_JSON_VALUE
)
@ApiOperation(value = "Returns sea food product by id ", notes = "Returns a list sea food product by id base on GET Method.", response = SeaFood.class)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Successful retrieval of sea food products by id! ", response = SeaFood.class),
@ApiResponse(code = 400, message = "Sea food resource not found ! "),
@ApiResponse(code = 500, message = "Internal server error") })
ResponseEntity<SeaFood> findSeaFoodById(@PathVariable("id") String id) throws ResourceNotFoundException {
Optional<SeaFood> seaFood = seaFoodRetailService.findProductById(id);
if (!seaFood.isPresent())
throw new ResourceNotFoundException();
try {
return new ResponseEntity<SeaFood>(
this.testAsyncAnnotationForMethodsWithReturnSeaFood(LocationEnum.TAIWAN,id)
, HttpStatus.OK
);
} catch (InterruptedException e) {
logger.error("InterruptedException fail : {}" , e.toString());
throw new ResourceNotFoundException();
} catch (ExecutionException e) {
logger.error("ExecutionException fail : {}" , e.toString());
throw new ResourceNotFoundException();
}
}
@PostMapping(
value="/${sea.food.api.taiwan}/create",
produces = MediaType.APPLICATION_JSON_VALUE
)
@ApiOperation(value = "Returns sea food product entity", notes = "Returns a sea food product by id base on request body.", response = List.class)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Successful retrieval of sea food product ! ", response = SeaFood.class),
@ApiResponse(code = 400, message = "Sea food resource not found ! "),
@ApiResponse(code = 500, message = "Internal server error") })
ResponseEntity<SeaFood> createSeaFood(@RequestBody SeaFood entity) throws SeaFoodRetailerGenericException {
return new ResponseEntity<>(
seaFoodRetailService.createSeaFood(entity)
,HttpStatus.CREATED
);
}
.....
.....
.....
}
定義模型敘述
@ApiModel(description = "海鮮模型")
public class SeaFood {
@ApiModelProperty(value = "海鮮序號", required = true)
String id;
@ApiModelProperty(value = "海鮮名稱", required = true)
String name;
@ApiModelProperty(value = "海鮮敘述", required = true)
String description;
@ApiModelProperty(value = "海鮮價格", required = true)
int price;
透過以上程式碼範例,各位開發者各做參考,實作一份你自己的API Spec 吧
透過下圖可看出API系統介紹與聯繫人資訊,且可看到小編定義的控制器名稱,並列出內部API所有描述的資訊內容及方法。
下圖可看到與小編定義的模型內容相同
透過下圖可看出透過Swagger 頁面上觸發API,並確認可成功取得回覆資訊喔。
tabnine-Cors-Registry-addMapping